#pragma once
#include <GraphicsBaseItem.h>
#include <GraphicsStretchOperation.h>
#include <GraphicsRotateOperation.h>
#include <GraphicsMoveOperation.h>
#include <GraphicsScaleOperation.h>
#include <GraphicsLineItem.h>
#include <mutex>

// Graphics构造器
template<typename T>
class GraphicsBuilder
{
public:
	T* build();
protected:
	// 创建操作类
	virtual void buildOperation();

	// 创建控制块
	virtual void buildPinkItem() = 0;

	// 创建吸附线
	virtual void buildAbsorptionLine();

	// 连接线
	void createLinePinkItem();

	// 中点控制
	void createMidPinkItem();

	// 角点控制
	void createCornerPinkItem();

	// 旋转控制
	void createRotatePinkItem();
protected:
	T* m_item = nullptr;
	std::once_flag m_flag;
};

template<typename T>
inline void GraphicsBuilder<T>::createLinePinkItem()
{
	assert(m_item);
	GraphicsPinkItem* leftLine = new GraphicsPinkItem(GraphicsPinkItem::LeftLine_Enum, m_item);
	GraphicsPinkItem* topLine = new GraphicsPinkItem(GraphicsPinkItem::TopLine_Enum, m_item);
	GraphicsPinkItem* rightLine = new GraphicsPinkItem(GraphicsPinkItem::RightLine_Enum, m_item);
	GraphicsPinkItem* bottomLine = new GraphicsPinkItem(GraphicsPinkItem::BottomLine_Enum, m_item);
	m_item->addPinkItem(leftLine);
	m_item->addPinkItem(topLine);
	m_item->addPinkItem(rightLine);
	m_item->addPinkItem(bottomLine);
}

template<typename T>
inline void  GraphicsBuilder<T>::createMidPinkItem()
{
	assert(m_item);
	GraphicsPinkItem* midTopItem = new GraphicsPinkItem(GraphicsPinkItem::MidTop_Enum, m_item);
	GraphicsPinkItem* midBottomItem = new GraphicsPinkItem(GraphicsPinkItem::MidBottom_Enum, m_item);
	GraphicsPinkItem* midRightItem = new GraphicsPinkItem(GraphicsPinkItem::MidRight_Enum, m_item);
	GraphicsPinkItem* midLeftItem = new GraphicsPinkItem(GraphicsPinkItem::MidLeft_Enum, m_item);
	m_item->addPinkItem(midTopItem);
	m_item->addPinkItem(midBottomItem);
	m_item->addPinkItem(midRightItem);
	m_item->addPinkItem(midLeftItem);
}

template<typename T>
inline void GraphicsBuilder<T>::createCornerPinkItem()
{
	assert(m_item);
	GraphicsPinkItem* leftTopItem = new GraphicsPinkItem(GraphicsPinkItem::TopLeft_Enum, m_item);
	GraphicsPinkItem* rightTopItem = new GraphicsPinkItem(GraphicsPinkItem::TopRight_Enum, m_item);
	GraphicsPinkItem* rightBottomItem = new GraphicsPinkItem(GraphicsPinkItem::BottomRight_Enum, m_item);
	GraphicsPinkItem* leftBottomItem = new GraphicsPinkItem(GraphicsPinkItem::BottomLeft_Enum, m_item);
	m_item->addPinkItem(leftTopItem);
	m_item->addPinkItem(rightTopItem);
	m_item->addPinkItem(rightBottomItem);
	m_item->addPinkItem(leftBottomItem);
}


template<typename T>
inline void GraphicsBuilder<T>::createRotatePinkItem()
{
	assert(m_item);
	GraphicsPinkItem* rotationItem = new GraphicsPinkItem(GraphicsPinkItem::Rotation_Enum, m_item);
	m_item->addPinkItem(rotationItem);
}


template<typename T>
inline T* GraphicsBuilder<T>::build()
{
	assert(m_item);
	std::call_once(m_flag, [=] {
		buildOperation();
		buildPinkItem();
		buildAbsorptionLine();
		m_item->initGraphics();
		});
	return m_item;
}

template<typename T>
inline void  GraphicsBuilder<T>::buildOperation()
{
	assert(m_item);
	GraphicsStretchOperation* stretchOperation = new GraphicsStretchOperation(m_item->getItemData(), m_item);
	QObject::connect(stretchOperation, &GraphicsStretchOperation::sigReachMaxSize, m_item, &GraphicsBaseItem::sigReachMaxSize);
	GraphicsRotateOperation* rotateOperation = new GraphicsRotateOperation(m_item->getItemData(), m_item);
	GraphicsMoveOperation* moveOperation = new GraphicsMoveOperation(m_item->getItemData(), m_item);
	GraphicsScaleOperation* scaleOperation = new GraphicsScaleOperation(m_item->getItemData(), m_item);
	QObject::connect(&m_item->getItemData(), &GraphicsBaseItemData::sigItemScaleChanged, scaleOperation, &GraphicsScaleOperation::onScale);

	m_item->addOperation(stretchOperation);
	m_item->addOperation(rotateOperation);
	m_item->addOperation(moveOperation);
	m_item->addOperation(scaleOperation);
}

template<typename T>
inline void GraphicsBuilder<T>::buildAbsorptionLine()
{
	assert(m_item);
	GraphicsLineItem* horialzal = new GraphicsLineItem(GraphicsLineType::HorizontalEnum, m_item);
	GraphicsLineItem* vertical = new GraphicsLineItem(GraphicsLineType::VerticalEnum, m_item);

	m_item->addAbsorptionLine(horialzal);
	m_item->addAbsorptionLine(vertical);
}
